GtkMagnifier: Add a resizing mode
authorMatthias Clasen <mclasen@redhat.com>
Sun, 21 Dec 2014 00:16:46 +0000 (19:16 -0500)
committerMatthias Clasen <mclasen@redhat.com>
Sun, 21 Dec 2014 00:16:46 +0000 (19:16 -0500)
In addition to the fixed-size mode that is used by the text view,
add a mode in which the magnifier requests enough size to render
the entire inspected widget at the current magnification. In this
mode, the magnifier will update its size when the size of the
inspected widget changes. Also, make the magnifier redraw on its
own whenever the inspected widget draws.

gtk/gtkmagnifier.c
gtk/gtkmagnifierprivate.h

index 0af11b7cee012c8070916779f6d486de46215bff..04f15bc961e5e0140695c8abc315b568bc872b04 100644 (file)
@@ -22,6 +22,7 @@
 
 enum {
   PROP_INSPECTED = 1,
+  PROP_RESIZE,
   PROP_MAGNIFICATION
 };
 
@@ -33,6 +34,9 @@ struct _GtkMagnifierPrivate
   gdouble magnification;
   gint x;
   gint y;
+  gboolean resize;
+  gulong draw_handler;
+  gulong resize_handler;
 };
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkMagnifier, _gtk_magnifier,
@@ -54,6 +58,10 @@ _gtk_magnifier_set_property (GObject      *object,
       _gtk_magnifier_set_magnification (GTK_MAGNIFIER (object),
                                         g_value_get_double (value));
       break;
+    case PROP_RESIZE:
+      _gtk_magnifier_set_resize (GTK_MAGNIFIER (object),
+                                 g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
     }
@@ -79,6 +87,9 @@ _gtk_magnifier_get_property (GObject    *object,
     case PROP_MAGNIFICATION:
       g_value_set_double (value, priv->magnification);
       break;
+    case PROP_RESIZE:
+      g_value_set_boolean (value, priv->resize);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
     }
@@ -96,12 +107,17 @@ _gtk_magnifier_draw (GtkWidget *widget,
   magnifier = GTK_MAGNIFIER (widget);
   priv = _gtk_magnifier_get_instance_private (magnifier);
 
+  if (priv->inspected == NULL)
+    return FALSE;
+
   if (!gtk_widget_is_visible (priv->inspected))
     return FALSE;
 
   gtk_widget_get_allocation (widget, &allocation);
   gtk_widget_get_allocation (priv->inspected, &inspected_alloc);
-  cairo_translate (cr, allocation.width / 2, allocation.height / 2);
+
+  if (!priv->resize)
+    cairo_translate (cr, allocation.width / 2, allocation.height / 2);
 
   x = CLAMP (priv->x, 0, inspected_alloc.width);
   y = CLAMP (priv->y, 0, inspected_alloc.height);
@@ -109,12 +125,133 @@ _gtk_magnifier_draw (GtkWidget *widget,
   cairo_save (cr);
   cairo_scale (cr, priv->magnification, priv->magnification);
   cairo_translate (cr, -x, -y);
+  g_signal_handler_block (priv->inspected, priv->draw_handler);
   gtk_widget_draw (priv->inspected, cr);
+  g_signal_handler_unblock (priv->inspected, priv->draw_handler);
   cairo_restore (cr);
 
   return TRUE;
 }
 
+static void
+gtk_magnifier_get_preferred_width (GtkWidget *widget,
+                                   gint      *minimum_width,
+                                   gint      *natural_width)
+{
+  GtkMagnifier *magnifier;
+  GtkMagnifierPrivate *priv;
+  gint width;
+
+  magnifier = GTK_MAGNIFIER (widget);
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  if (priv->resize && priv->inspected)
+    width = priv->magnification * gtk_widget_get_allocated_width (priv->inspected);
+  else
+    width = 0;
+
+  *minimum_width = width;
+  *natural_width = width;
+}
+
+static void
+gtk_magnifier_get_preferred_height (GtkWidget *widget,
+                                    gint      *minimum_height,
+                                    gint      *natural_height)
+{
+  GtkMagnifier *magnifier;
+  GtkMagnifierPrivate *priv;
+  gint height;
+
+  magnifier = GTK_MAGNIFIER (widget);
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  if (priv->resize && priv->inspected)
+    height = priv->magnification * gtk_widget_get_allocated_height (priv->inspected);
+  else
+    height = 0;
+
+  *minimum_height = height;
+  *natural_height = height;
+}
+
+static void
+resize_handler (GtkWidget     *widget,
+                GtkAllocation *alloc,
+                GtkWidget     *magnifier)
+{
+  gtk_widget_queue_resize (magnifier);
+}
+
+static void
+connect_resize_handler (GtkMagnifier *magnifier)
+{
+  GtkMagnifierPrivate *priv;
+
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  if (priv->inspected && priv->resize)
+    priv->resize_handler = g_signal_connect (priv->inspected, "size-allocate",
+                                             G_CALLBACK (resize_handler), magnifier);
+}
+
+static void
+disconnect_resize_handler (GtkMagnifier *magnifier)
+{
+  GtkMagnifierPrivate *priv;
+
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  if (priv->resize_handler)
+    {
+      g_signal_handler_disconnect (priv->inspected, priv->resize_handler);
+      priv->resize_handler = 0;
+    }
+}
+
+static gboolean
+draw_handler (GtkWidget     *widget,
+              cairo_t       *cr,
+              GtkWidget     *magnifier)
+{
+  gtk_widget_queue_draw (magnifier);
+  return FALSE;
+}
+
+static void
+connect_draw_handler (GtkMagnifier *magnifier)
+{
+  GtkMagnifierPrivate *priv;
+
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  if (priv->inspected)
+    priv->draw_handler = g_signal_connect (priv->inspected, "draw",
+                                           G_CALLBACK (draw_handler), magnifier);
+}
+
+static void
+disconnect_draw_handler (GtkMagnifier *magnifier)
+{
+  GtkMagnifierPrivate *priv;
+
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  if (priv->draw_handler)
+    {
+      g_signal_handler_disconnect (priv->inspected, priv->draw_handler);
+      priv->draw_handler = 0;
+    }
+}
+
+static void
+_gtk_magnifier_destroy (GtkWidget *widget)
+{
+  _gtk_magnifier_set_inspected (GTK_MAGNIFIER (widget), NULL);
+
+  GTK_WIDGET_CLASS (_gtk_magnifier_parent_class)->destroy (widget);
+}
+
 static void
 _gtk_magnifier_class_init (GtkMagnifierClass *klass)
 {
@@ -124,7 +261,10 @@ _gtk_magnifier_class_init (GtkMagnifierClass *klass)
   object_class->set_property = _gtk_magnifier_set_property;
   object_class->get_property = _gtk_magnifier_get_property;
 
+  widget_class->destroy = _gtk_magnifier_destroy;
   widget_class->draw = _gtk_magnifier_draw;
+  widget_class->get_preferred_width = gtk_magnifier_get_preferred_width;
+  widget_class->get_preferred_height = gtk_magnifier_get_preferred_height;
 
   g_object_class_install_property (object_class,
                                    PROP_INSPECTED,
@@ -140,6 +280,13 @@ _gtk_magnifier_class_init (GtkMagnifierClass *klass)
                                                         P_("magnification"),
                                                         1, G_MAXDOUBLE, 1,
                                                         G_PARAM_READWRITE));
+  g_object_class_install_property (object_class,
+                                   PROP_RESIZE,
+                                   g_param_spec_boolean ("resize",
+                                                         P_("resize"),
+                                                         P_("resize"),
+                                                         FALSE,
+                                                         G_PARAM_READWRITE));
 }
 
 static void
@@ -156,6 +303,7 @@ _gtk_magnifier_init (GtkMagnifier *magnifier)
 
   gtk_widget_set_has_window (widget, FALSE);
   priv->magnification = 1;
+  priv->resize = FALSE;
 }
 
 GtkWidget *
@@ -193,7 +341,14 @@ _gtk_magnifier_set_inspected (GtkMagnifier *magnifier,
   if (priv->inspected == inspected)
     return;
 
+  disconnect_draw_handler (magnifier);
+  disconnect_resize_handler (magnifier);
+
   priv->inspected = inspected;
+
+  connect_draw_handler (magnifier);
+  connect_resize_handler (magnifier);
+
   g_object_notify (G_OBJECT (magnifier), "inspected");
 }
 
@@ -252,6 +407,9 @@ _gtk_magnifier_set_magnification (GtkMagnifier *magnifier,
   priv->magnification = magnification;
   g_object_notify (G_OBJECT (magnifier), "magnification");
 
+  if (priv->resize)
+    gtk_widget_queue_resize (GTK_WIDGET (magnifier));
+
   if (gtk_widget_is_visible (GTK_WIDGET (magnifier)))
     gtk_widget_queue_draw (GTK_WIDGET (magnifier));
 }
@@ -267,3 +425,37 @@ _gtk_magnifier_get_magnification (GtkMagnifier *magnifier)
 
   return priv->magnification;
 }
+
+void
+_gtk_magnifier_set_resize (GtkMagnifier *magnifier,
+                           gboolean      resize)
+{
+  GtkMagnifierPrivate *priv;
+
+  g_return_if_fail (GTK_IS_MAGNIFIER (magnifier));
+
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  if (priv->resize == resize)
+    return;
+
+  priv->resize = resize;
+
+  gtk_widget_queue_resize (GTK_WIDGET (magnifier));
+  if (resize)
+    connect_resize_handler (magnifier);
+  else
+    disconnect_resize_handler (magnifier);
+}
+
+gboolean
+_gtk_magnifier_get_resize (GtkMagnifier *magnifier)
+{
+  GtkMagnifierPrivate *priv;
+
+  g_return_val_if_fail (GTK_IS_MAGNIFIER (magnifier), FALSE);
+
+  priv = _gtk_magnifier_get_instance_private (magnifier);
+
+  return priv->resize;
+}
index 5e916900dd0b814188369d96845e9d231a3639ce..84b79e1c44cb4f31430a2ac44b1087233ec3410d 100644 (file)
@@ -59,6 +59,10 @@ void        _gtk_magnifier_set_magnification (GtkMagnifier *magnifier,
                                               gdouble       magnification);
 gdouble     _gtk_magnifier_get_magnification (GtkMagnifier *magnifier);
 
+void        _gtk_magnifier_set_resize        (GtkMagnifier *magnifier,
+                                              gboolean      resize);
+gboolean    _gtk_magnifier_get_resize        (GtkMagnifier *magnifier);
+
 G_END_DECLS
 
 #endif /* __GTK_MAGNIFIER_H__ */